package com.aliyun.heiyu.powermaster.server.agent;

import com.aliyun.heiyu.powermaster.server.IStrategyExecutor;
import io.grpc.stub.StreamObserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

import com.aliyun.heiyu.powermaster.proto.PowerStrategy;
import com.aliyun.heiyu.powermaster.proto.PowerCommand;
import com.aliyun.heiyu.powermaster.proto.ReportStatusRequest;

public class AgentManager {
    private static Logger log = LoggerFactory.getLogger(AgentManager.class);

    private Map<String, Agent> agents;

    private Map<PowerStrategy, IStrategyExecutor> strategies;

    public AgentManager() {
        // TODO: store in etcd
        agents = new HashMap<String, Agent>();
        strategies = new HashMap<PowerStrategy, IStrategyExecutor>();
    }

    public Agent get(String id) {
        return agents.get(id);
    }

    public List<Agent> getByLabel(String label) {
        List<Agent> labelAgents = new ArrayList<Agent>();
        for (Agent agent : agents.values()) {
            if (agent.hasLabel(label)) {
                labelAgents.add(agent);
            }
        }

        return labelAgents;
    }

    public List<Agent> getAll(String id) {
        List<Agent> all = getByLabel(id);
        Agent agent = get(id);
        if (agent != null) {
            all.add(agent);
        }

        return all;
    }

    public void disableStrategy(PowerStrategy strategy) {
        strategies.remove(strategy);
    }

    /** register agent with {@code id}. */
    public void register(String id, int power, long freq) {
        Agent agent = agents.get(id);
            synchronized (agents) {
                if(agent == null) {
                    agent = new Agent(id, power, freq);
                    agents.put(id, agent);
                }
            }


        for (IStrategyExecutor executor : strategies.values()) {
            executor.onAgentRegister(agent);
        }
    }

    public void subscribe(String id, StreamObserver<PowerCommand> responseObserver) {
        Agent agent = agents.get(id);
        if (agent == null) {
            responseObserver.onCompleted();
        } else {
            agent.subscribe(responseObserver);
        }
    }

    public void update(ReportStatusRequest req) {
        String id = req.getId();
        Agent agent = agents.get(id);
        if (agent != null) {
            agent.update(req.getPower(), req.getFreqsList().get(0));
            for (IStrategyExecutor executor : strategies.values()) {
                executor.onAgentReport(agent);
            }
        }
    }

    /** unregister agent with {@code id}. */
    public void unregister(String id) {
        Agent agent = agents.get(id);

        synchronized (agents) {
            if (agent != null) {
                agents.remove(id);
                for (IStrategyExecutor executor : strategies.values()) {
                    executor.onAgentRemove(agent);
                }
            }
        }
    }

}
